using RadioTimer.Models;
using RadioTimer.Services;
using System.Globalization;
using System.Threading;

namespace RadioTimer.Services
{
    /// <summary>
    /// 时间报时服务实现类
    /// 实现ITimeChimeService接口，提供核心的报时功能
    /// 通过定时器实现精准的时间检查，支持多种报时内容组合
    /// </summary>
    public class TimeChimeService : ITimeChimeService
    {
        #region 私有字段
        
        /// <summary>
        /// 数据存储服务实例，用于加载和保存设置与统计信息
        /// </summary>
        private readonly IDataStorageService _dataStorage;
        
        /// <summary>
        /// 文本转语音服务实例，用于语音播报
        /// </summary>
        private readonly ITextToSpeechService _textToSpeech;
        
        /// <summary>
        /// 定时器实例，用于定时检查报时条件
        /// </summary>
        private Timer? _timer;
        
        /// <summary>
        /// 服务运行状态标志
        /// </summary>
        private bool _isServiceRunning;
        
        /// <summary>
        /// 用于取消异步操作的令牌源
        /// </summary>
        private CancellationTokenSource? _cancellationTokenSource;
        
        /// <summary>
        /// 上次报时时间，用于防止重复执行
        /// </summary>
        private DateTime _lastChimeTime = DateTime.MinValue;
        
        #endregion

        #region 公共属性
        
        /// <summary>
        /// 获取服务是否正在运行的状态
        /// </summary>
        public bool IsServiceRunning => _isServiceRunning;

        #endregion

        #region 事件
        
        /// <summary>
        /// 报时触发事件
        /// 当成功执行报时时触发，传递报时的具体时间
        /// </summary>
        public event EventHandler<DateTime>? ChimeTriggered;
        
        /// <summary>
        /// 服务状态变更事件
        /// 当服务状态发生变化时触发，传递状态描述信息
        /// </summary>
        public event EventHandler<string>? ServiceStatusChanged;

        #endregion

        #region 构造函数
        
        /// <summary>
        /// 初始化TimeChimeService实例
        /// </summary>
        /// <param name="dataStorage">数据存储服务实例</param>
        /// <param name="textToSpeech">文本转语音服务实例</param>
        public TimeChimeService(IDataStorageService dataStorage, ITextToSpeechService textToSpeech)
        {
            _dataStorage = dataStorage;
            _textToSpeech = textToSpeech;
            _cancellationTokenSource = new CancellationTokenSource();
            
            // 记录日志
            Services.DebugLogger.WriteLine("TimeChimeService 初始化完成");
        }
        
        #endregion

        #region 公共方法
        
        /// <summary>
        /// 启动报时服务
        /// 初始化定时器并开始定时检查报时条件
        /// </summary>
        /// <returns>异步任务</returns>
        public Task StartServiceAsync()
        {
            Services.DebugLogger.WriteLine("开始启动报时服务");
            // 如果服务已在运行，直接返回
            if (_isServiceRunning) return Task.CompletedTask;

            // 创建定时器，每秒检查一次时间，确保不会错过整点报时
            _timer = new Timer(CheckTime, null, TimeSpan.Zero, TimeSpan.FromSeconds(1));
            _isServiceRunning = true;
            ServiceStatusChanged?.Invoke(this, "Service started");
            return Task.CompletedTask;
        }

        /// <summary>
        /// 停止报时服务
        /// 释放定时器资源并停止所有报时活动
        /// </summary>
        /// <returns>异步任务</returns>
        public async Task StopServiceAsync()
        {
            Services.DebugLogger.WriteLine("开始停止报时服务");
            // 如果服务未运行，直接返回
            if (!_isServiceRunning) return;

            try
            {
                // 取消令牌
                _cancellationTokenSource?.Cancel();
                
                // 释放定时器资源
                _timer?.Dispose();
                _timer = null;
                _isServiceRunning = false;
                
                // 重置上次报时时间
                _lastChimeTime = DateTime.MinValue;
                
                ServiceStatusChanged?.Invoke(this, "Service stopped");
            }
            catch (Exception ex)
            {
                Services.DebugLogger.WriteError($"Error stopping service: {ex.Message}");
            }
        }

        /// <summary>
        /// 异步获取下一次报时的时间
        /// 根据当前设置计算下一个启用的报时时间点
        /// </summary>
        /// <returns>返回下一次报时的时间，如果没有启用的报时则返回null</returns>
        public async Task<DateTime?> GetNextChimeTimeAsync()
        {
            Services.DebugLogger.WriteLine("开始获取下一次报时时间");
            try
            {
                var settings = await _dataStorage.LoadAppSettingsAsync();
                if (!settings.IsChimeServiceEnabled) return null;

                var now = DateTime.Now;
                var nextHour = now.Hour;
                var nextDay = 0;

                // 查找下一个启用的报时时间
                for (int i = 0; i < 24; i++)
                {
                    var checkHour = (now.Hour + i + 1) % 24;
                    if (checkHour <= now.Hour && i > 0) nextDay = 1;

                    if (settings.HourlySettings.GetValueOrDefault(checkHour)?.IsEnabled == true)
                    {
                        return new DateTime(now.Year, now.Month, now.Day, checkHour, 0, 0).AddDays(nextDay);
                    }
                }

                return null;
            }
            catch (Exception ex)
            {
                Services.DebugLogger.WriteError($"Error getting next chime time: {ex.Message}");
                return null;
            }
        }
        
        #endregion

        #region 私有方法
        
        /// <summary>
        /// 定时检查报时条件的回调方法
        /// 每秒执行一次，检查是否需要执行报时
        /// </summary>
        /// <param name="state">定时器状态参数（未使用）</param>
        private async void CheckTime(object? state)
        {
            // 检查取消令牌
            if (_cancellationTokenSource?.Token.IsCancellationRequested == true)
                return;

            try
            {
                var now = DateTime.Now;


                Services.DebugLogger.WriteLine($"报时检查: {now.Minute}:{now.Second},上次:{_lastChimeTime}");
                // 检查是否为整点
                if (now.Minute == 0 && now.Second < 3)
                {
                    // 检查是否在最近一小时内已经执行过报时，防止重复执行
                    if ((now - _lastChimeTime).TotalMinutes < 55)
                    {
                        // 如果在最近一小时内已经报时过，则跳过
                        return;
                    }
                    // 更新上次报时时间
                    _lastChimeTime = now;

                    var settings = await _dataStorage.LoadAppSettingsAsync();
                    
                    // 检查全局报时服务是否启用
                    if (!settings.IsChimeServiceEnabled) return;

                    var hourSettings = settings.HourlySettings.GetValueOrDefault(now.Hour);
                    // 检查当前小时是否启用报时
                    if (hourSettings?.IsEnabled != true) return;

                    Services.DebugLogger.WriteLine($"执行报时播放: {_lastChimeTime}");
                    // 执行报时播放
                    await PlayChimeAsync(now, hourSettings);
                    
                    
                    // 更新统计信息
                    var statistics = await _dataStorage.LoadStatisticsAsync();
                    statistics.IncrementChimeCount();
                    await _dataStorage.SaveStatisticsAsync(statistics);

                    // 触发报时事件
                    ChimeTriggered?.Invoke(this, now);
                }
            }
            catch (Exception ex)
            {
                Services.DebugLogger.WriteError($"Error in CheckTime: {ex.Message}");
            }
        }

        /// <summary>
        /// 异步播放报时语音
        /// 根据设置生成报时文本并重复播放指定次数
        /// </summary>
        /// <param name="time">报时的具体时间</param>
        /// <param name="settings">该小时的报时设置</param>
        /// <returns>异步任务</returns>
        private async Task PlayChimeAsync(DateTime time, TimeChimeSettings settings)
        {
            Services.DebugLogger.WriteLine($"开始播放报时语音: {time}");
            // 检查取消令牌
            if (_cancellationTokenSource?.Token.IsCancellationRequested == true)
                return;

            try
            {
                // 生成报时文本内容
                var chimeText = GenerateChimeText(time, settings);
                
                // 根据设置的重复次数播放
                for (int i = 0; i < settings.RepeatCount; i++)
                {
                    // 检查取消令牌
                    if (_cancellationTokenSource?.Token.IsCancellationRequested == true)
                        return;

                    await _textToSpeech.SpeakAsync(chimeText, settings.Volume);
                    
                    // 如果不是最后一次播放，等待1秒后继续
                    if (i < settings.RepeatCount - 1)
                    {
                        // 检查取消令牌
                        if (_cancellationTokenSource?.Token.IsCancellationRequested == true)
                            return;
                            
                        await Task.Delay(1000); // 重复播放间隔1秒
                    }
                }
            }
            catch (Exception ex)
            {
                Services.DebugLogger.WriteError($"Error playing chime: {ex.Message}");
            }
        }

        /// <summary>
        /// 生成报时文本内容
        /// 根据用户设置组合时间、日期、星期、农历等信息
        /// </summary>
        /// <param name="time">当前时间</param>
        /// <param name="settings">报时设置</param>
        /// <returns>格式化的报时文本</returns>
        private string GenerateChimeText(DateTime time, TimeChimeSettings settings)
        {
            var parts = new List<string>();

            // 添加基本时间信息
            parts.Add($"现在时间是{time.Hour}点整");

            // 根据设置添加公历日期
            if (settings.IncludeGregorianCalendar)
            {
                parts.Add($"{time.Year}年{time.Month}月{time.Day}日");
            }

            // 根据设置添加星期信息
            if (settings.IncludeWeekday)
            {
                // 使用CalendarHelper获取星期信息
                var calendarHelper = new CalendarHelper();
                var dateInfo = calendarHelper.GetDateTidyInfo(time);
                parts.Add(dateInfo.DayInWeek);
            }

            // 根据设置添加农历信息
            if (settings.IncludeLunarCalendar)
            {
                // 使用CalendarHelper获取农历信息
                var calendarHelper = new CalendarHelper();
                var lunarDate = calendarHelper.GetLunarDateString(time);
                parts.Add($"农历{lunarDate}");
            }

            // 用逗号连接所有部分
            return string.Join("，", parts);
        }
        
        #endregion
        
        #region IDisposable Support
        
        private bool disposedValue = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // 释放托管资源
                    _cancellationTokenSource?.Cancel();
                    _cancellationTokenSource?.Dispose();
                    _cancellationTokenSource = null;
                    
                    _timer?.Dispose();
                    _timer = null;
                }

                disposedValue = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        
        #endregion
    }
}